特定セキュリティグループのみ EC2インスタンスへ関連付けできるように制限する IAMポリシー
やりたいこと
EC2インスタンスへのセキュリティグループ関連付けを制限したいです。 具体的には特定セキュリティグループのみ付与が可能、 ほかセキュリティグループはインスタンスへ関連付けできないようにします。
これを行うモチベーションは「インスタンスの通信制限の徹底」です。 セキュリティグループは 許可リスト方式 を取ります。 そのため、セキュリティグループの付与により インバウンド/アウトバウンドの許可範囲が増えます。 AWS利用者の意図しないセキュリティグループの付与により 「SSH/RDP フルオープンになっている」といった事態になってしまう...そういった懸念がある場合の解決案の1つです。
どうやって実現するか
セキュリティグループへタグ付けを行い、「特定セキュリティグループ」と 「それ以外」を分類します。
このタグをベースに、許可/拒否を決定する IAMポリシーを作成します。
本ブログでは「 AdminManaged = yes タグ
を付与した セキュリティグループ」と
「それ以外のセキュリティグループ」の前提で実装を進めます。
IAMポリシー(メイン)
まずは「タグが AdminManaged = yes
以外 のセキュリティグループ」の
関連付けアクションを禁止する IAMポリシーです。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "DenyNotAllowedSGAttach", "Effect": "Deny", "Action": "ec2:ModifyNetworkInterfaceAttribute", "Resource": "arn:aws:ec2:*:*:security-group/*", ], "Condition": { "StringNotEqualsIfExists": { "aws:ResourceTag/AdminManaged": "yes" } } } ] }
▼ 以下 ステートメント解説
EC2インスタンスのセキュリティグループ関連付け設定の変更は ec2:ModifyNetworkInterfaceAttribute で行います。
全てのセキュリティグループのリソースARNは
arn:aws:ec2:*:*:security-group/*
で表せます。
(参考: Amazon EC2 で定義されるリソースタイプ)
Condition を使って
セキュリティグループの AdminManagedタグが "yes" かどうか 判断しています。
条件キーの aws:ResourceTag/AdminManaged
が
リソースに付与されている AdminManaged
タグ値を表します。
ケース(SGのタグ情報) | 条件の真偽 | 【結果】 |
---|---|---|
AdminManaged = yes | StringNotEquals により false | Denyされない |
AdminManaged ≠ yes | StringNotEquals により true | Denyされる |
AdminManaged タグ無し | IfExists により true | Denyされる |
(参考) 活用している条件演算子( StringNotEquals
や IfExists
) の詳細は
以下参照ください。
IAMポリシー(タグ編集のガードレール)
前述のIAMポリシーだけでは不十分です。
なぜなら、AWS利用者自身で AdminManaged
タグを追加/更新/削除できるためです。
「特定セキュリティグループ」の枠組みを破壊されないようにするための
ガードレールが必要です。
今回は以下内容の制限を設けて実現しました。
AdminManaged
タグを持つ SG … 任意タグの追加/更新/削除を禁止するAdminManaged
タグを持たない SG …AdminManaged
タグの追加を禁止する
この 2つの制限を IAMポリシーに書くと以下のようになります。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "DenyTagOperationsForManagedSG", "Effect": "Deny", "Action": [ "ec2:CreateTags", "ec2:DeleteTags" ], "Resource": "arn:aws:ec2:*:*:security-group/*", "Condition": { "Null": { "aws:ResourceTag/AdminManaged": false } } }, { "Sid": "DenyTagCreationForNonManagedSG", "Effect": "Deny", "Action": "ec2:CreateTags", "Resource": "arn:aws:ec2:*:*:security-group/*", "Condition": { "Null": { "aws:ResourceTag/AdminManaged": true, "aws:RequestTag/AdminManaged": false } } } ] }
1つ目のステートメント解説
セキュリティグループに対して、タグの操作 ec2:CreateTags, ec2:DeleteTags
を Condition 次第で禁止します。
Condition では Null を活用しています。条件キーが存在するかどうか、判断します。
ケース(SGのタグ情報) | 条件の真偽 | 【結果】 |
---|---|---|
AdminManaged タグ 有り | true | Denyされる |
AdminManaged タグ 無し | false | Denyされない |
結果として 「AdminManaged タグが付与されているセキュリティグループ」には タグ操作ができなくなります。
2つ目のステートメント解説
セキュリティグループに対して、タグの追加/更新 ec2:CreateTags
を Condition 次第で禁止します。
Condition では 同じく Null を活用しています。条件キーが存在するかどうか、判断します。
ケース#1(リソースタグ) | 条件#1 | ケース#2(リクエストタグ) | 条件#2 | 条件の真偽 | 【結果】 |
---|---|---|---|---|---|
AdminManaged 有り | false | AdminManaged 有り | true | false | Deny されない |
AdminManaged 有り | false | AdminManaged 無し | false | false | Deny されない |
AdminManaged 無し | true | AdminManaged 有り | true | true | Deny される |
AdminManaged 無し | true | AdminManaged 無し | false | false | Deny されない |
上の表の 条件#1は "aws:ResourceTag/AdminManaged": true
部分
条件#2 は "aws:RequestTag/AdminManaged": false
部分を表しています。
最終的に各条件の AND
が計算されます。
結果として「AdminManaged タグが付与されていないセキュリティグループ」に対して 「AdminManaged タグ を追加」できなくなります。
(参考) 本IAMポリシーで説明した Null や Conditionの評価ロジックについては以下参考になります。
- 【小ネタ】 AWS IAMポリシーの Conditionで使える条件演算子 “Null” の使いみちを考える | DevelopersIO
- 複数のキーまたは値による条件の作成 - AWS Identity and Access Management
試してみる
以下 権限を付与した IAMロールを使って検証しました。
- PowerUserAccess
- 前述の「IAMポリシー(メイン)」
- 前述の「IAMポリシー(タグ編集のガードレール)」
セキュリティグループとして以下 4つを使ってテストします。
aws ec2 describe-security-groups --filters Name=group-name,Values="*ManagedSG*" --output table \ --query "SecurityGroups[].[GroupName, GroupId, Tags[?Key=='AdminManaged']|[0].Value]" # ----------------------------------------------------- # | DescribeSecurityGroups | # +------------------+------------------------+-------+ # | NonManagedSG2 | sg-031xxxxxxxxxxxxxx | None | → AdminManagedタグ無しのSG # | NonManagedSG1 | sg-058xxxxxxxxxxxxxx | no | → AdminManaged=no のSG # | AdminManagedSG2 | sg-089xxxxxxxxxxxxxx | yes | → AdminManaged=yes のSG # | AdminManagedSG1 | sg-08cxxxxxxxxxxxxxx | yes | → AdminManaged=yes のSG # +------------------+------------------------+-------+
EC2インスタンスには予め AdminManagedSG1 をアタッチしています。
aws ec2 describe-instances --filters Name=instance-id,Values=$INSTANCE --output table \ --query "Reservations[].Instances[].SecurityGroups" # --------------------------------------------- # | DescribeInstances | # +-----------------------+-------------------+ # | GroupId | GroupName | # +-----------------------+-------------------+ # | sg-08cxxxxxxxxxxxxxx | AdminManagedSG1 | # +-----------------------+-------------------+
EC2インスタンスのSG関連付け設定の変更
以下のように AdminManaged=yes の SGは自由に付け外しできます。
# AdminManagedSG2 を付ける aws ec2 modify-network-interface-attribute --network-interface-id $ENI \ --groups $AdminManagedSG1 $AdminManagedSG2 ### Check aws ec2 describe-instances --filters Name=instance-id,Values=$INSTANCE --output table \ --query "Reservations[].Instances[].[SecurityGroups]" # --------------------------------------------- # | DescribeInstances | # +-----------------------+-------------------+ # | GroupId | GroupName | # +-----------------------+-------------------+ # | sg-08cxxxxxxxxxxxxxx | AdminManagedSG1 | # | sg-089xxxxxxxxxxxxxx | AdminManagedSG2 | # +-----------------------+-------------------+
# AdminManagedSG2 を外す aws ec2 modify-network-interface-attribute --network-interface-id $ENI \ --groups $AdminManagedSG1 ### Check aws ec2 describe-instances --filters Name=instance-id,Values=$INSTANCE --output table \ --query "Reservations[].Instances[].[SecurityGroups]" # --------------------------------------------- # | DescribeInstances | # +-----------------------+-------------------+ # | GroupId | GroupName | # +-----------------------+-------------------+ # | sg-08cxxxxxxxxxxxxxx | AdminManagedSG1 | # +-----------------------+-------------------+
それ以外の SGはそもそも付けることができません。
aws ec2 modify-network-interface-attribute --network-interface-id $ENI \ --groups $AdminManagedSG1 $NonManagedSG1 # An error occurred (UnauthorizedOperation) when calling the ModifyNetworkInterfaceAttribute operation: You are not authorized to perform this operation. ...
aws ec2 modify-network-interface-attribute --network-interface-id $ENI \ --groups $AdminManagedSG1 $NonManagedSG2 # An error occurred (UnauthorizedOperation) when calling the ModifyNetworkInterfaceAttribute operation: You are not authorized to perform this operation. ...
SGのタグ付け
AdminManaged=yes の SGに対して、タグの追加、更新、削除はできません。
### 追加 aws ec2 create-tags --resources $AdminManagedSG1 --tags Key=Hoge,Value=Fuga # An error occurred (UnauthorizedOperation) when calling the CreateTags operation: You are not authorized to perform this operation. ... ### 更新 aws ec2 create-tags --resources $AdminManagedSG1 --tags Key=AdminManaged,Value=no # An error occurred (UnauthorizedOperation) when calling the CreateTags operation: You are not authorized to perform this operation. ... ### 削除 aws --profile kensho-r ec2 delete-tags --resources $AdminManagedSG1 --tags Key=AdminManaged # An error occurred (UnauthorizedOperation) when calling the DeleteTags operation: You are not authorized to perform this operation. ...
ほかSGは AdminManagedタグは追加できません 。 それ以外のタグは追加できます。
### AdminManaged タグの追加 --> ダメ aws ec2 create-tags --resources $NonManagedSG2 --tags Key=AdminManaged,Value=yes # An error occurred (UnauthorizedOperation) when calling the CreateTags operation: You are not authorized to perform this operation. ... ### AdminManaged 以外タグの追加 --> OK aws ec2 create-tags --resources $NonManagedSG2 --tags Key=Name,Value=NonManagedSG2 aws ec2 describe-security-groups --filters Name=group-id,Values=$NonManagedSG2 --query "SecurityGroups[].Tags" --output table # --------------------------- # | DescribeSecurityGroups | # +-------+-----------------+ # | Key | Value | # +-------+-----------------+ # | Name | NonManagedSG2 | # +-------+-----------------+
おわりに
EC2インスタンスへの セキュリティグループアタッチ/デタッチ制御例を紹介しました。
「どのようにポリシー設計するか」だけでなく 「このポリシーをどのように使って、運用していくか」も実際に使う際には 重要になってきます。しっかりと規則化、ドキュメント化する必要があるでしょう。
参考になれば幸いです。
参考
- AWS Documents
- DevelopersIO